package com.dayu.finecomm.iot.handle;

import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static io.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpResponseStatus.UNSUPPORTED_MEDIA_TYPE;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dayu.finecomm.aop.ClassLevelAnnotation;
import com.dayu.finecomm.aop.MethodLevelAnnotation;
import com.dayu.finecomm.iot.IotDriverAdapter;

/**
 * IotPlat消息处理，URL解析
 * 
 * @author XuJialiang
 * @since 2017-09-04 10:22:12
 * @version V1.0.0
 */
@ClassLevelAnnotation
public class IotPlatInboundHandler extends ChannelInboundHandlerAdapter {
	static Logger LOGGER = LoggerFactory.getLogger(IotPlatInboundHandler.class);

	/**
	 * 订阅服务名称
	 */
	private static final String SUBSCRIBE_BINDDEVICE_LABEL = "bindDevice"; // 设备绑定
	private static final String SUBSCRIBE_DATACHANGE_LABEL = "deviceDataChanged"; // 设备数据上报
	private static final String SUBSCRIBE_DEVICEDELETE_LABEL = "deviceDeleted"; // 删除设备
	private static final String SUBSCRIBE_COMMANDRSP_LABEL = "commandRsp"; // 命令响应
	private static final String SUBSCRIBE_DATASCHANGE_LABEL = "deviceDatasChanged"; // 批量设备数据上报
	private static final String SUBSCRIBE_DEVINFOCHANGE_LABEL = "deviceInfoChanged";// 设备信息变化
	private static final String SUBSCRIBE_RULEEVENT_LABEL = "ruleEvent"; // 规则事件

	/**
	 * 订阅服务对应索引号
	 */
	private static final int SUBSCRIBE_BIND_DEVICE = 1;
	private static final int SUBSCRIBE_DATA_CHANGE = 2;
	private static final int SUBSCRIBE_DEVICE_DELETE = 3;
	private static final int SUBSCRIBE_COMMAND_RSP = 4;
	private static final int SUBSCRIBE_DATAS_CHANGE = 5;
	private static final int SUBSCRIBE_DEVINFO_CHANGE = 6;
	private static final int SUBSCRIBE_RULE_EVENT = 7;

	/**
	 * 正则表达式，从URI中获取订阅服务名称
	 */
	private static final String PATTERN = "/ycb/iot/(\\w+)/(\\w+)";

	/**
	 * Subscribe Map
	 */
	private Map<String, Integer> mSubscribeMap;

	/**
	 * 订阅服务对应索引号
	 */
	private int mSubscribe;

	/**
	 * Iot 应用ID
	 */
	private String mAppId;

	/**
	 * 协议处理适配器
	 */
	IotDriverAdapter mDriverAdapter;

	public IotPlatInboundHandler(IotDriverAdapter adapter) {
		mSubscribeMap = new HashMap<String, Integer>();

		mSubscribeMap.put(SUBSCRIBE_BINDDEVICE_LABEL, SUBSCRIBE_BIND_DEVICE);
		mSubscribeMap.put(SUBSCRIBE_DATACHANGE_LABEL, SUBSCRIBE_DATA_CHANGE);
		mSubscribeMap
				.put(SUBSCRIBE_DEVICEDELETE_LABEL, SUBSCRIBE_DEVICE_DELETE);
		mSubscribeMap.put(SUBSCRIBE_COMMANDRSP_LABEL, SUBSCRIBE_COMMAND_RSP);
		mSubscribeMap.put(SUBSCRIBE_DATASCHANGE_LABEL, SUBSCRIBE_DATAS_CHANGE);
		mSubscribeMap.put(SUBSCRIBE_DEVINFOCHANGE_LABEL,
				SUBSCRIBE_DEVINFO_CHANGE);
		mSubscribeMap.put(SUBSCRIBE_RULEEVENT_LABEL, SUBSCRIBE_RULE_EVENT);

		mSubscribe = SUBSCRIBE_DATA_CHANGE;
		mAppId = "";
		mDriverAdapter = adapter;
	}

	@Override
	public void channelActive(ChannelHandlerContext ctx) throws Exception {
		LOGGER.debug("iot plat comming");

		if (null != mDriverAdapter) {
			mDriverAdapter.initChannel(ctx);
		}

		ctx.fireChannelActive();
	}

	@MethodLevelAnnotation
	@Override
	public void channelRead(ChannelHandlerContext ctx, Object msg)
			throws Exception {

		if (msg instanceof HttpRequest) {
			HttpRequest request = (HttpRequest) msg;

			String uri = request.getUri();

			LOGGER.debug("Uri:" + uri);

			Pattern pattern = Pattern.compile(PATTERN);
			Matcher m = pattern.matcher(uri);

			if (m.find()) {
				mAppId = m.group(1);
				if (mSubscribeMap.containsKey(m.group(2))) {
					mSubscribe = mSubscribeMap.get(m.group(2));
				} else {
					LOGGER.info("404 Not Found, Can not support uri: " + uri);

					throw new Exception("404");
				}

				LOGGER.info("subscribe: " + mSubscribe + ", uri: " + uri);
			} else {
				LOGGER.info("404 Not Found, Can not support uri: " + uri);

				throw new Exception("404");
			}
		}

		if (msg instanceof HttpContent) {
			HttpContent content = (HttpContent) msg;

			if (content.content().readableBytes() > 0) {
				String buf = content.content().toString(
						io.netty.util.CharsetUtil.UTF_8);

				JSONObject jsonContent = JSON.parseObject(buf);

				jsonContent.put("appId", mAppId);

				// 处理相关订阅服务上报数据
				switch (mSubscribe) {
				case SUBSCRIBE_BIND_DEVICE:
					jsonContent.put("subscribe", SUBSCRIBE_BINDDEVICE_LABEL);
					ctx.fireChannelRead(jsonContent);
					break;
				case SUBSCRIBE_DEVICE_DELETE:
					jsonContent.put("subscribe", SUBSCRIBE_DEVICEDELETE_LABEL);
					ctx.fireChannelRead(jsonContent);
					break;
				case SUBSCRIBE_COMMAND_RSP:
					jsonContent.put("subscribe", SUBSCRIBE_COMMANDRSP_LABEL);
					ctx.fireChannelRead(jsonContent);
					break;
				case SUBSCRIBE_DATA_CHANGE:
					jsonContent.put("subscribe", SUBSCRIBE_DATACHANGE_LABEL);
					ctx.fireChannelRead(jsonContent);
					break;
				case SUBSCRIBE_DATAS_CHANGE:
					jsonContent.put("subscribe", SUBSCRIBE_DATASCHANGE_LABEL);
					ctx.fireChannelRead(jsonContent);
					break;
				default:
					LOGGER.info("Can not subscribe: " + mSubscribe);
					break;
				}
			}

			responseHttpOK(ctx);
			ctx.close();
		}
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.flush();
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
			throws Exception {
		LOGGER.error(cause.getMessage());

		if (0 == cause.getMessage().compareTo("404")) {
			responseHttpError(ctx, NOT_FOUND);
		} else {
			responseHttpError(ctx, UNSUPPORTED_MEDIA_TYPE);
		}

		ctx.close();
	}

	/**
	 * 向IOT平台成功返回
	 * 
	 * @param ctx
	 * @throws Exception
	 */
	private void responseHttpOK(ChannelHandlerContext ctx) throws Exception {
		String res = "Welcome to HDKJ";

		JSONObject jsonObj = new JSONObject();
		jsonObj.put("msg", res);

		FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK,
				Unpooled.wrappedBuffer(jsonObj.toString().getBytes("UTF-8")));

		response.headers().set(CONTENT_TYPE, "application/json");
		response.headers().set(CONTENT_LENGTH,
				response.content().readableBytes());

		ctx.write(response);
		ctx.flush();
	}

	/**
	 * 向IOT平台错误返回
	 * 
	 * @param ctx
	 * @throws Exception
	 */
	private void responseHttpError(ChannelHandlerContext ctx,
			HttpResponseStatus rspStatus) throws Exception {
		String res = rspStatus.toString();

		JSONObject jsonObj = new JSONObject();
		jsonObj.put("msg", res);

		FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
				rspStatus, Unpooled.wrappedBuffer(jsonObj.toString().getBytes(
						"UTF-8")));

		response.headers().set(CONTENT_TYPE, "application/json");
		response.headers().set(CONTENT_LENGTH,
				response.content().readableBytes());

		ctx.write(response);
		ctx.flush();
	}
}
